﻿#ifndef CHATCLIENT_H
#define CHATCLIENT_H

#include "chatdatapack.h"
#include <QHash>
#include <QObject>
#include <QTcpSocket>
#include <QTextStream>
#include <functional>

class TcpChatter : public QObject {
  Q_OBJECT
public:
  typedef std::function<void()> MesgCallBackType;
  typedef std::function<void(const QStringList &)> CmdCallBackType;

  explicit TcpChatter(const QString &id, QObject *parent = nullptr);
  ~TcpChatter();

  QString group() { return Group; }

public slots:
  void setID(const QString &id);
  void setGroup(const QString &groupname);
  /**
   * @brief 进行socket初始化
   *
   * @note 如果需要在子线程中使用TcpChatter，
   * 那么需要在子线程中调用这个函数
   */
  void init();

  bool connectToServer(const QString &ip, const int &port);

  void sendTo(const QString &mesg, const QString &id);
  void sendToGroup(const QString &mesg, const QString &group);
  void broadcast(const QString &mesg);
  void sendCommandTo(const QString &cmd, const QStringList &param,
                     const QString &id);
  void sendCommandToGroup(const QString &cmd, const QStringList &param,
                          const QString &group);

  void regMesgCallback(const QString &mesg, TcpChatter::MesgCallBackType func);
  void cleanMesgCallback();
  void regCmdCallback(const QString &cmd, TcpChatter::CmdCallBackType func);
  void cleanCmdCallback();

signals:
  void message(const QString &mesg);
  void message(const QString &mesg, const QString &sender);
  void command(const QString &cmd, const QStringList &param);
  void command(const QString &cmd, const QStringList &param,
               const QString &sender);

private:
  ChatDataPack pack;

  QTcpSocket *Socket;
  QString ServerIP;
  int ServerPort;

  QString ID;
  QString Group;

  bool isInit = false;
  bool isConnectServer = false;

  QHash<QString, QVector<MesgCallBackType>> MesgCallbackMap;
  QHash<QString, QVector<CmdCallBackType>> CmdCallbackMap;

  void updateGroup();

  bool CheckMesg(const QString &mesg);

  void parse(const QByteArray &data);

  QString printPrefix();
  void Info(const QString &Info);
  void Warning(const QString &Info);

  void writeToSocket(const QString &str);

private slots:
  void readTcpMesg();
};
#endif // CHATCLIENT_H
